package com.uwlaser.cut;

import com.uwlaser.http.exception.HttpException;
import com.uwlaser.modules.system.service.SysExternalSocketLogService;
import com.uwlaser.socket.exception.TcpSocketException;
import com.uwlaser.utils.SpringContextHolder;
import com.uwlaser.webservice.exception.WebServiceException;
import lombok.RequiredArgsConstructor;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.util.ObjectUtils;

import java.lang.reflect.Method;
import java.net.SocketException;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author LiuZhiHui
 * @version 1.0
 * @description: TODO
 * @date 2022/8/17 10:40
 */
@Aspect
@Component
@RequiredArgsConstructor
@Order(2)
public class BaseMethodAspect {

    /**
     * 切入实现类容器
     * */
    Map<String, BaseMethodCut> cutServiceMap = new ConcurrentHashMap<>();

    private final BaseMethodExceptionHandler baseMethodExceptionHandler;

    /** 切入点
     * @author LiuZhiHui
     * @description: TODO
     * @param:
     * @return: void
     * @date: 2022/8/17 12:00
     */
    @Pointcut("@annotation(com.uwlaser.annotation.BaseMethodTag)")
    public void pointcut() {
    }

    /** 环绕切入
     * @author LiuZhiHui
     * @description: TODO
     * @param: joinPoint
     * @return: java.lang.Object
     * @date: 2022/8/17 11:59
     */
    @Around("pointcut()")
    public Object around(ProceedingJoinPoint joinPoint) throws Exception {
        //时间
        long time = System.currentTimeMillis();
        // 切入类容器无值
        if(cutServiceMap.size() == 0) {
            // 从IOC容器中获取实现类
            setCutServiceMap();
        }
        // 获取目标方法名称
        String name = joinPoint.getSignature().getName();
        // 获取当前方法切入类
        BaseMethodCut cutService = getCurrentMethodCutService(name);

        // 没有找到注解标注方法的切入实现类直接返回
        if(ObjectUtils.isEmpty(cutService)){
//            StringBuffer msg = new StringBuffer("未找到当前注解标注方法 ")
//                    .append(name).append("() 的切入实现类");
//            throw new ProgramRunningException(msg.toString());
            // 执行目标方法
            try {
                return joinPoint.proceed();
            } catch (Throwable e) {
                throw new RuntimeException(e.getMessage(),e);
            }
        }

        // 执行前置方法
        try {
            cutService.before(joinPoint);
        }catch (Exception e){
            //异常处理
            baseMethodExceptionHandler.handler(e,time);
        }

        // 执行目标方法
        Object returnValue = null;
        try {
            returnValue = joinPoint.proceed();
        } catch (Throwable e) {
            if(e instanceof TcpSocketException || e instanceof WebServiceException || e instanceof HttpException){
                //异常处理
                baseMethodExceptionHandler.handler((Exception) e,time);
            } else {
                throw new RuntimeException(e.getMessage(),e);
            }
        }

        // 执行后置方法
        try {
            cutService.after(joinPoint,returnValue);
        } catch (Exception e){
            //异常处理
            baseMethodExceptionHandler.handler(e,time);
        }
        return returnValue;
    }

    private BaseMethodCut getCurrentMethodCutService(String name) {
        // 遍历切入类容器
        for (String key : cutServiceMap.keySet()) {
            BaseMethodCut baseMethodCut = cutServiceMap.get(key);
            Method method = baseMethodCut.getMethodClass();
            if(method.getName().equals(name)){
                return baseMethodCut;
            }
        }
        return null;
    }

    /** 从IOC容器中获取切入实现类
     * @author LiuZhiHui
     * @description: TODO
     * @param:
     * @return: void
     * @date: 2022/8/17 12:03
     */
    public void setCutServiceMap() {
        cutServiceMap = SpringContextHolder.getBeansOfType(BaseMethodCut.class);
    }

}
